var path = require('path');
var fs = require('fs');
var Consts = require('../../../util/consts');
var utils = require('../../../util/utils');
var gameService = require('../../../services/killer/gameService');
var messageService = require('../../../services/messageService');
var fileBasePath = '/home/work';
var uploadDir = path.join(fileBasePath, '/uploads/KillerGame');
var RoomRemote = require('../remote/roomRemote');

var killerUserDao = require('../../../dao/killer/killerUserDao');
var killerMarkDao = require('../../../dao/killer/killerMarkDao');

var logger = require('pomelo-logger').getLogger('KillerGame', __filename);

module.exports = function (app) {
    return new KillerHandler(app);
};


var KillerHandler = function (app) {
    this.app = app;
    this.roomRemote = new RoomRemote(app);
};
var handler = KillerHandler.prototype;

var admin = 'backgroundAdmin';


var status = {
    live: 1,
    dead: 0
};

var found = {
    found: 1,
    notFound: 0
};

/**
 * 上传Mark
 * @param msg {file: binaryString, filename: xxx}
 * @param session
 * @param next
 */
handler.uploadMark = function (msg, session, next) {
    var rid = session.get('rid');
    var username = msg.username;

    var filename = msg.filename + '_' + username + '_' + rid;


    var filepath = path.join(uploadDir, filename);

    fs.writeFile(filepath, new Buffer(msg.file, 'base64'), function (err) {
        if (err) {
            logger.error('Upload Mark error! %j', err);
            next(null, {
                code: 401
            });
            return;
        }
    });
    next(null, {
        code: 200, url: filename
    });
};

/**
 * 上传mark超过120秒
 * @param msg
 * @param session
 * @param next
 */
handler.uploadMarkTimeOut = function (msg, session, next) {
    var rid = session.get('rid');
    var username = msg.username;
    var self = this;

    killerUserDao.killUser(rid, username, function (err, user) {
        self._sendMessage(admin, username, {action: 'wasKilled', reason: 'upload mark timeout'}, rid);
        next(null, {code: 200});
    });
};

/**
 * 下载Mark
 * @param msg {filename: xxx, username: xxx}
 * @param session
 * @param next
 * @return {code: 200, file: data}
 */
handler.downloadMark = function (msg, session, next) {
    var filename = msg.filename;
    var username = msg.username;

    filename = path.join(uploadDir, filename);

    fs.readFile(filename, 'base64', function (err, data) {
        if (err) {
            next(null, {
                code: 404
            });
        } else {

            next(null, {
                code: 200,
                file: data
            });
        }
    });
};

/**
 * 东西已经放好
 * @param msg
 * @param session
 * @param next
 * @return {code: 200(others), role: killer(commoner)}
 */
handler.endHide = function (msg, session, next) {
    var rid = session.get('rid');
    var username = msg.username;
    var urls = msg.urls;

    killerUserDao.getUsersByRid(rid, function (err, users) {
        if (err || users == null || users.length == 0) {
            next(null, {
                code: 400,
                msg: 'room does not exist'
            });
            return;
        }

        var i = 0;
        var currentUser;
        for (; i < users.length; i++) {
            var user = users[i];
            if (user['name'] == username) {
                currentUser = user;
                for (var j = 0; j < urls.length; j++) {

                    killerMarkDao.createMark(username, rid, found.notFound, username, urls[j], function (err, mark) {
                        if (err) {
                            logger.error('create mark error! %j', err);
                        }
                    });
                }
                break;
            }
        }

        if (i >= users.length) {
            next(null, {
                code: 400,
                msg: 'user does not exist'
            });
            return;
        }


        var role = currentUser.role;

        next(null, {
            code: 200,
            role: role
        });
    });


};

/**
 * 玩家确认自己的角色
 * @param msg
 * @param session
 * @param next
 */
handler.confirmRole = function (msg, session, next) {
    var self = this;
    var username = msg.username;
    var confirm = msg.confirm;
    var role = msg.role;
    var rid = session.get('rid');

    killerUserDao.updateUser(rid, username, confirm, true, Consts.KillerPhase.CONFIRM, function (err, user) {
        if (!!err) {
            logger.error('update user error! %j', err);
        } else {
            killerUserDao.getNoConfirmUsers(rid, function (err, users) {
                if (err) {
                    logger.error('confirm role error! %j', err);
                    next(null, {
                        code: 500
                    });
                } else {
                    if (users === null || users.length === 0) {
                        // all users confirm
                        self._dispatchMarks(rid);
                        next(null, {
                            code: 200
                        });
                    } else {
                        next(null, {
                            code: 200
                        });
                    }

                }
            });
        }
    });

};

/**
 * 获得玩家的序号
 * @param msg
 * @param session
 * @param next
 */
handler.getSeqByUsername = function (msg, session, next) {
    var self = this;
    var rid = session.get('rid');
    var username = msg.username;

    killerUserDao.getUserByID(username, rid, function (err, killerUser) {
        if (err) {
            next(null, {
                code: 400
            });
        } else {
            next(null, {
                code: 200,
                seq: killerUser.seq
            });
        }
    });
};

handler.dispatchMarks = function (rid) {
    this._dispatchMarks(rid);
};

/**
 *  分发mark
 *  rule1：杀手的mark不能分发给杀手。
 *  rule2：一轮只能取一个玩家的一个mark。
 *  rule3：不能重复分发同一个mark给不同的玩家。
 *  @param rid 房间号
 */
handler._dispatchMarks = function (rid) {
    var self = this;
    killerUserDao.getAliveUsersByRid(rid, function (err, users) {
        var userCount = users.length;

        var killers = [];
        var commoners = [];
        for (var i = 0; i < userCount; i++) {
            var user = users[i];
            if (user.role === Consts.KillerRole.KILLER) {
                killers.push(user);
            } else if (user.role === Consts.KillerRole.COMMONER) {
                commoners.push(user);
            } else {
                logger.error("unknown user role: %j", user);
            }

        }


        killerMarkDao.getAliveMarksByRid(rid, function (err, marks) {

            var dispatch = {};
            for (var i = 0; i < userCount; i++) {
                dispatch[users[i]['name']] = [];
            }
            for (var j = 0; j < marks.length; j++) {
                var mark = marks[j];
                dispatch[mark['username']].push(mark);
            }


            // dispatch mark to killer
            var j = 0; // commoner index
            for (var i = 0; i < killers.length; i++) {
                var commoner = commoners[j];
                var killer = killers[i];

                var tempMarks = dispatch[commoner['name']];
                var mark;
                for (var markIndex = 0; markIndex < tempMarks.length; markIndex++) {
                    var myMark = tempMarks[markIndex];
                    if (myMark.isFinding) {
                        continue;
                    } else {
                        myMark.isFinding = 1;
                        mark = myMark;
                    }
                    if ((markIndex === tempMarks.length - 1) && (mark === null)) {
                        mark = tempMarks[markIndex];
                    }
                }

                self._doDispatchMark(admin, killer.name, {
                    fromRole: commoner.role,
                    url: mark.url,
                    action: Consts.KillerAction.START_SEEK
                }, rid);

                j++;
            }
            // dispatch mark to commoner
            var k = 0; // killer index
            for (var i = 0; i < commoners.length; i++) {
                var commonerTakeMark = commoners[i]; // 等待分mark的平民

                var commonerOwnMark;
                if (j < commoners.length) {
                    commonerOwnMark = commoners[j]; // 从该平民取得mark
                    j++;
                } else if (k < killers.length) {
                    commonerOwnMark = killers[k];
                    k++;
                } else {
                    logger.error("dispatch mark error. rid: %j", rid);
                }

                var tempMarks = dispatch[commonerOwnMark['name']];
                var mark;
                for (var markIndex = 0; markIndex < tempMarks.length; markIndex++) {
                    var iterMark = tempMarks[markIndex];
                    if (iterMark.isFinding) {
                        continue;
                    } else {
                        iterMark.isFinding = 1;
                        mark = iterMark;
                    }
                }
                if (mark === null && tempMarks !== null && tempMarks.length > 0) {
                    mark = tempMarks[tempMarks.length - 1];
                }

                self._doDispatchMark(admin, commonerTakeMark.name, {
                    fromRole: commonerOwnMark.role,
                    url: mark.url,
                    action: Consts.KillerAction.START_SEEK
                }, rid);
            }
        });

    });

};

/**
 * 分发mark消息
 * @param from
 * @param target
 * @param content
 * @param rid
 * @private
 */
handler._doDispatchMark = function (from, target, content, rid) {
    var self = this;
    self._sendMessage(from, target, content, rid);
};

/**
 *
 * @param msg {beFoundRole: 被找到的角色, username: xxx, url: xxx}
 * @param sesseion
 * @param next
 */
handler.found = function (msg, session, next) {
    var self = this;
    var rid = session.get('rid');
    var username = msg.username;
    var url = msg.url;
    var beFoundRole = msg.beFoundRole;

    killerMarkDao.updateMark(url, username, function (err, mark) {
        if (err) {
            next(null, {
                code: 500
            });
            return;
        }
        if (beFoundRole === Consts.KillerRole.COMMONER) {
            // commoner get killed
            killerMarkDao.getMarkByUrl(url, rid, function (err, mark) {
                if (err || mark === null) {
                    if (err) {
                        logger.error("found error: %j", err);
                    } else {
                        logger.error("can not find mark by url: %j", url);
                    }

                    next(null, {
                        code: 500
                    });
                } else {
                    var username = mark.username;
                    killerUserDao.killUser(rid, username, function (err, user) {
                        if (err) {
                            logger.error("uid: %j, kill user failed: %j", username, err);
                            next(null, {
                                code: 500
                            });
                        } else {
                            // tell room who was killed
                            self._sendMessage(admin, '*', {
                                action: Consts.KillerAction.GET_KILLED,
                                username: username,
                                url: url,
                                haveWord: true
                            }, rid);
                            self._checkGameStatus(rid, function (err, code) {
                                if (code !== 200) {
                                    next(null, {
                                        code: 200
                                    });
                                } else {
                                    next(null, {
                                        code: 200
                                    });
                                }

                            });
                        }
                    });
                }
            });
        } else {
            // killer mark was found
            var killerName = mark.username;
            killerMarkDao.getAliveMarksByRid(rid, function (err, marks) {
                if (err) {
                    next(null, {
                        code: 500
                    });
                } else {
                    if (marks.length === 0) {
                        // killer get killed
                        killerUserDao.killUser(rid, username, function (err, user) {
                            if (err) {
                                logger.error("uid: %j, kill user failed: %j", username, err);
                                next(null, {
                                    code: 500
                                });
                            } else {
                                // tell room who was killed
                                self._sendMessage(admin, '*', {
                                    action: Consts.KillerAction.GET_KILLED,
                                    username: username,
                                    url: url,
                                    haveWord: true
                                }, rid);
                                self._checkGameStatus(rid, function (err, code) {
                                    if (code !== 200) {
                                        next(null, {
                                            code: 200
                                        });

                                    } else {
                                        next(null, {
                                            code: 200
                                        });
                                    }

                                });
                            }
                        });
                    } else {
                        // current user finds next
                        // killerMarkDao.getAliveMarksByRid(rid, function (err, marks) {
                        //     if (err) {
                        //         next(null, {
                        //             code: 500
                        //         });
                        //     } else {
                        //         next(null, {
                        //             code: 200,
                        //             nextUrl: marks[0].url
                        //         });
                        //     }
                        // });
                        // 平安夜
                        self._sendMessage(admin, '*', {
                            action: Consts.KillerAction.GET_KILLED,
                            url: url,
                            username: "none",
                            haveWord: false
                        }, rid);
                        self._checkGameStatus(rid, function (err, code) {
                            if (code !== 200) {
                                next(null, {
                                    code: 200
                                });

                            } else {
                                next(null, {
                                    code: 200
                                });
                            }

                        });
                    }
                }
            });
        }
    });

};
handler._checkGameStatus = function (rid, cb) {
    var self = this;
    // check game status
    gameService.checkGameStatus(rid, function (err, code, winners) {
        if (err) {
            utils.invokeCallback(cb, {code: err.number, msg: err.message}, null);
        } else {
            if (code === gameService.GameStatus.KILLER_WIN) {
                self._sendMessage(admin, '*', {
                    winner: Consts.KillerRole.KILLER,
                    action: Consts.KillerAction.GAME_OVER,
                    usernames: winners
                }, rid);
                utils.invokeCallback(cb, null, 202);
            } else if (code === gameService.GameStatus.COMMONER_WIN) {
                self._sendMessage(admin, '*', {
                    winner: Consts.KillerRole.COMMONER,
                    action: Consts.KillerAction.GAME_OVER,
                    usernames: winners
                }, rid);
                utils.invokeCallback(cb, null, 201);
            } else {
                // tell room who was killed
                self._sendMessage(admin, '*', {
                    action: Consts.KillerAction.STOP_FIND
                }, rid);
                // 找到的人等待
                utils.invokeCallback(cb, null, 200);
            }
        }
    });
};

handler._sendMessage = function (from, target, content, rid) {
    var self = this;
    var action = content.action || '';
    messageService.sendMessageWithAction(from, target, JSON.stringify(content), rid,
        Consts.GameRoute.KILLER_GAME, self.app, content.action);
};